package csc411;

import java.net.*;
import java.io.*;

import java.util.ArrayList;

public class ObserversManager {

	private ArrayList observers;
	private DatagramSocket callbackSocket;
	private int port;

	public ObserversManager() {
		this.observers = new ArrayList();
		this.port = 9877;
	}

	public void register(InetAddress address, int port, int interval) {

		// check if observer already exists in the list
		if (this.isDuplicate(address, port)) {
			// update interval
			try {
				Observer observer = this.getObserver(address, port);
				observer.updateInterval(interval);
				System.out.println("[CALLBACK] Update interval for observer: (" + address.getHostAddress() + ":" + port + ") for " + interval + "secs");

			} catch (Exception e) {
				System.out.println(e.getMessage());
			}
		} else {

			Observer newObserver = new Observer(address, port, interval);

			this.observers.add(newObserver);

			System.out.println("[CALLBACK] New observer added: (" + address.getHostAddress() + ":" + port + ") for " + interval + "secs");


		}
	}

	private Observer getObserver(InetAddress address, int port) throws Exception {
		Observer observer = null;

		for (int i = 0; i < this.observers.size(); i++) {

			observer = (Observer) this.observers.get(i);

			if (observer.equals(address, port)) {
				return observer;
			}

		}

		if (observer == null) {
			throw new Exception("Observer does not exist");
		}

		return observer;
	}

	private boolean isDuplicate(InetAddress address, int port) {
		boolean value = false;

		for (int i = 0; i < this.observers.size(); i++) {

			Observer observer = (Observer) this.observers.get(i);

			if (observer.equals(address, port)) {
				return true;
			}

		}

		return value;
	}

	public void callback(String message) {

		if (this.observers.size() == 0) {
			System.out.println("[CALLBACK] No observers");
		}

		// start callback socket
		try {

			this.callbackSocket = new DatagramSocket(this.port);

		} catch (SocketException e) {
			System.out.println(e.toString());
		}

		// prepare callback message
		byte[] callbackData = new byte[1024];
		callbackData = message.getBytes();

		for (int i = 0; i < this.observers.size(); i++) {

			Observer observer = (Observer) this.observers.get(i);

			// if it has expired, remove
			// else send callback message to observer

			if (observer.hasExpired()) {

				System.out.println("[CALLBACK] Observer has expired " + observer.toString());
				this.observers.remove(i);
				i--;

			} else {

				// prepare callback packet
				DatagramPacket callbackPacket =
						new DatagramPacket(
						callbackData, callbackData.length,
						observer.getAddress(), observer.getPort());

				try {
					// send callback message to observer
					this.callbackSocket.send(callbackPacket);

					System.out.println("[CALLBACK] Callback sent to " + observer.toString());

				} catch (IOException e) {
					System.out.println(e.toString());
				}

			}

		} // end for

		this.callbackSocket.close();
	} // end callback

	public void printObserversList() {
		System.out.println("Observers list");
		System.out.println("--------------");
		if (this.observers.size() == 0) {

			System.out.println("  Empty");

		} else {

			for (int i = 0; i < this.observers.size(); i++) {

				Observer observer = (Observer) this.observers.get(i);
				System.out.println(i + ":" + observer.toString());

			}
		}

		System.out.println();

	}
}
